from django.shortcuts import render
from django.views import View
import json
from django import http
from django_redis import get_redis_connection
import base64, pickle

from apps.goods.models import SKU
# Create your views here.

class CartSelectAllView(View):
    """全选购物车"""

    def put(self, request):
        """
        :param request:
        :return:
        PUT请求地址/carts/selection/
        """
        # 接收参数
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected', True)

        # 校验参数
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseForbidden('参数selected有误')

        # 判断用户是否登录
        user_id = request.user.id
        if request.user.is_authenticated:
            # 用户已登录，操作redis购物车
            redis_conn = get_redis_connection('carts')

            #获取所有hash数据
            item_dict = redis_conn.hgetall('carts_%s' %user_id)

            #获取所有字典数据
            sku_ids = item_dict.keys()

            #判断用户是否全选
            if selected:
                # 全选
                # redis_conn.sadd('selected_%s' % user.id, *sku_ids)

                for i in sku_ids:

                    redis_conn.sadd('selected_%s' % user_id, i)
            else:
                # 取消全选
                # redis_conn.srem('selected_%s' % user.id, *sku_ids)
                for i in sku_ids:

                    redis_conn.srem('selected_%s' % user_id, i)

            return http.JsonResponse({'code': 0,
                                      'errmsg': '全选购物车成功'})

        else:
            # 用户未登录，操作cookie购物车
            cookie_cart = request.COOKIES.get('carts')

            response = http.JsonResponse({'code': 0,
                                          'errmsg': '全选购物车成功'})

            # 判断用户是否全选
            if cookie_cart:
                cart_dict = pickle.loads(base64.b64decode(cookie_cart.encode()))

                #遍历所有购物车数据
                for sku_id in cart_dict.keys():
                    cart_dict[sku_id]['selected'] = selected

                cart_data = base64.b64encode(pickle.dumps(cart_dict)).decode()

                #重写购物车数据写入到cookie
                response.set_cookie('carts', cart_data)

            return response


class CartsView(View):
    """购物车管理"""

    def post(self, request):
        """添加购物车
        POST请求地址	/carts/
        """
        #接收参数
        data_dict = json.loads(request.body.decode())
        sku_id = data_dict.get('sku_id')
        count = data_dict.get('count')
        selected = data_dict.get('selected', True)

        #检验参数
        if not all([sku_id, count]):
            return http.JsonResponse({'code':400,
                                      'errmsg':'缺少必传参数'})

        try:
            SKU.objects.get(id=sku_id)

        except SKU.DoesNotExist:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数sku_id错误'})

        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数count错误'})

        if not isinstance(selected, bool):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数selected错误'})

        #实现核心逻辑
        # 判断是否登录用户
        if request.user.is_authenticated:
            #登录用户,新增redis数据
            #创建redis对象
            redis_conn = get_redis_connection('carts')

            user_id = request.user.id

            #建立管道
            pl= redis_conn.pipeline()
            #增加sku_id和count到hash
            pl.hincrby('carts_%s'%user_id, sku_id, count)

            #增加sku_id和count到set
            if selected:
                pl.sadd('selected_%s'%user_id, sku_id)
            pl.execute()

            return http.JsonResponse({'code': 0, 'errmsg': 'OK'})
        else:
            #未登录用户,新增cookie数据字符串类型
            cart_str = request.COOKIES.get('carts')

            # cookie中是否存在购物车cart_str
            if cart_str:
                #从cookie中读取购物车字典
                # 从cookie中读取之前保存的密文数据
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))

            else:
                cart_dict = {}

            # 添加购物车数据到购物车字典
            if sku_id in cart_dict:
                origin_count = cart_dict[sku_id]['count']
                count += origin_count

            cart_dict[sku_id] = {
                'count':count,
                'selected':selected
            }

            #购物车字典转字符串写入到cookie
            cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response = http.JsonResponse({'code':0, 'errmsg':'ok'})

            response.set_cookie('carts', cookie_cart_str)

            return response


    def get(self, request):
        """实现查询购物车的逻辑"""
        # 判断用户是否登录
        if request.user.is_authenticated:
            # 如果用户已登录，查询redis购物车
            user_id = request.user.id
            redis_conn = get_redis_connection('carts')
            # 查询hash中的商品和数量 redis_cart = {b'sku_id1': b'count1', b'sku_id2': b'coun2'}
            redis_cart = redis_conn.hgetall('carts_%s' % user_id)
            # 查询set中的勾选状态 redis_selected = [b'sku_id1']
            redis_selected = redis_conn.smembers('selected_%s' % user_id)

            # 将redis购物车转成可操作的对象：将redis_cart和redis_selected里面的数据合并到一个购物车字典中
            # 使用redis_cart和redis_selected构造一个跟cookie购物车字典一样的字典
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in redis_selected
                }
        else:
            # 如果用户未登录，查询cookie购物车
            # 从cookie中读取购物车字典
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        """
        {
            "sku_id1":{
                "count":"1",
                "selected":True
            },
            "sku_id3":{
                "count":"3",
                "selected":False
            }
        }
        """
        # 读取购物车里面的商品信息
        sku_ids = cart_dict.keys()
        sku_model_list = SKU.objects.filter(id__in=sku_ids)

        cart_skus = []
        for sku in sku_model_list:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price,
                'count': cart_dict[sku.id]['count'],
                'selected': cart_dict[sku.id]['selected'],
                'amount': sku.price * cart_dict[sku.id]['count']
            })

        # 响应结果
        return http.JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_skus': cart_skus})


    def put(self, request):
        """实现修改购物车的逻辑
        修改购物车和新增购物车百分之九十九是相同的
        """
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        # 如果前端没有传递selected参数，我们给个默认值True,默认被勾选
        selected = json_dict.get('selected', True)

        # 校验参数
        if not all([sku_id, count]):
            return http.JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code': 400, 'errmsg': '参数sku_id错误'})
        try:
            # 使用int类型强转count，如果count不是数字，自动会抛出异常
            count = int(count)
        except Exception:
            return http.JsonResponse({'code': 400, 'errmsg': '参数count错误'})
        # 校验selected类型
        if not isinstance(selected, bool):
            return http.JsonResponse({'code': 400, 'errmsg': '参数selected错误'})

        # 判断用户是否登录
        if request.user.is_authenticated:
            # 如果用户已登录，修改redis购物车
            # 由于前端向后端发送的是修改后的数据，所以后端直接覆盖写入即可
            user_id = request.user.id
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            pl.hset('carts_%s' % user_id, sku_id, count)
            if selected:
                pl.sadd('selected_%s' % user_id, sku_id)
            else:
                pl.srem('selected_%s' % user_id, sku_id)
            pl.execute()

            # 在修改成功后，记得将修改后的数据返回给前端，实现局部刷新的效果
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected
            }

            return http.JsonResponse({'code': 0, 'errmsg': 'OK', 'cart_sku': cart_sku})
        else:
            # 如果用户未登录，修改cookie购物车
            # 由于前端向后端发送的是修改后的数据，所以后端直接覆盖写入即可
            # 从cookie中读取购物车字典
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

            # 修改购物车字典
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 将购物车字典转字符串并写入到cookie
            cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

            # 构造响应数据
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected
            }
            response = http.JsonResponse({'code': 0, 'errmsg': 'OK', 'cart_sku': cart_sku})
            response.set_cookie('carts', cookie_cart_str)
            return response


    def delete(self, request):
        """实现删除购物车的逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.JsonResponse({'code': 400, 'errmsg': '参数sku_id错误'})

        # 判断用户是否登录
        if request.user.is_authenticated:
            # 如果用户已登录，删除redis购物车
            user_id = request.user.id
            # 创建连接到redis的对象
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            # 删除hash中的购物车数据
            pl.hdel('carts_%s' % user_id, sku_id)
            # 删除set中的勾选状态
            pl.srem('selected_%s' % user_id, sku_id)
            pl.execute()

            return http.JsonResponse({'code': 0, 'errmsg': 'OK'})
        else:
            # 如果用户未登录，删除cookie购物车
            # 从cookie中读取购物车字典
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

            # 删除购物车字典中的key
            # 注意点：在删除字典的key时，必须判断字典的key是否存在，只能删除存在的key,如果删了不存在的key,会报错
            if sku_id in cart_dict:
                del cart_dict[sku_id]

            # 将购物车字典转字符串并写入到cookie
            cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()

            response = http.JsonResponse({'code': 0, 'errmsg': 'OK'})
            response.set_cookie('carts', cookie_cart_str)
            return response

